#include "Demo.h"
#include "resource.h"
#include <windowsx.h>

//////////////////////////////////////////////////////////////////////////
// CDemoApp
//////////////////////////////////////////////////////////////////////////
CDemoApp::CDemoApp()
{

}

CDemoApp::~CDemoApp()
{

}

bool CDemoApp::InitInstance()
{
	m_pMainWnd = new CDemoWnd();
	m_pMainWnd->ShowWindow(SW_SHOW);
																   
	return true;
}

//////////////////////////////////////////////////////////////////////////
// CDemoWnd
//////////////////////////////////////////////////////////////////////////
#define MSGHANDLE(nMsg, MsgProc)  {(nMsg), (&CDemoWnd::MsgProc)}

const CDemoWnd::TMSGMAP CDemoWnd::MsgMapTable[] = {
	MSGHANDLE(WM_CREATE,	OnCreate),
	MSGHANDLE(WM_DESTROY,	OnDestroy), 
	MSGHANDLE(WM_PAINT,		OnPaint),
};

CDemoWnd::CDemoWnd()
{
	Create(_T("Demo Brush"), WS_OVERLAPPEDWINDOW, 0, 0, 800, 480, NULL);
}

CDemoWnd::~CDemoWnd()
{

}

LRESULT	 CDemoWnd::WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	for (int ii = 0; ii < sizeof(MsgMapTable) / sizeof(*MsgMapTable); ii++)
	{
		if (nMsg == MsgMapTable[ii].m_nMsg)
		{
			(this->*MsgMapTable[ii].m_MsgProc)(hWnd, nMsg, wParam, lParam);
			break;
		}
	}

	return __super::FinalWndProc(hWnd, nMsg, wParam, lParam);
}

LRESULT CDemoWnd::OnCreate(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	CenterWindow();

	return 0;
}

LRESULT CDemoWnd::OnDestroy(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	PostQuitMessage(0);

	return 0;
}

LRESULT CDemoWnd::OnPaint(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hDC = BeginPaint(hWnd, &ps);
	
	RECT rtGrids[4];

	PartitionGrid(hDC, rtGrids, 4);

	DemoSolidBrush(hDC, rtGrids[0]);
	
	DemoPatternBrush(hDC, rtGrids[1]);

	DemoHatchBrush(hDC, rtGrids[2]);
	
	DemoKindOfBrush(hDC, rtGrids[3]);

	EndPaint(hWnd, &ps);

	return 1;
}

void CDemoWnd::PartitionGrid(HDC hDC, RECT* prtGrids, int nGridCount)
{
	assert(0 < nGridCount);

	//--: Display current brush color
	COLORREF clColr = GetDCBrushColor(hDC);
	TCHAR szCurBrushInfo[256];
	_stprintf_s(szCurBrushInfo, 256, _T("   Current Brush Color: RGB(%d:%d:%d)"), GetRValue(clColr), GetGValue(clColr), GetBValue(clColr));
	TextOut(hDC, 0, 0, szCurBrushInfo, _tcslen(szCurBrushInfo));

	//--: Grids rect area
	RECT rtClient;
	GetClientRect(m_hWnd, &rtClient);
	InflateRect(&rtClient, -10, -10);
	OffsetRect(&rtClient, 0, 10);

	//==: calculate every grid rect and paint color
	HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, GetStockObject(DC_BRUSH));
	SetDCBrushColor(hDC, RGB(200, 200, 200));

	const int nGridH	= ((rtClient.bottom - rtClient.top) / nGridCount);
	for (int ii = 0; ii < nGridCount; ii++)
	{
		int nGridTop = rtClient.top + ii * nGridH;
		SetRect(&prtGrids[ii], rtClient.left, nGridTop, rtClient.right, nGridTop + nGridH);
		Rectangle(hDC, prtGrids[ii].left, prtGrids[ii].top, prtGrids[ii].right, prtGrids[ii].bottom);
	}
	SelectObject(hDC, hOldBrush);
	
	return;
}	

void CDemoWnd::DemoSolidBrush(HDC hDC, RECT& rtGrid)
{
	InflateRect(&rtGrid, -5, -5);

	int nSavedDC = SaveDC(hDC);

	HBRUSH hBrush	 = CreateSolidBrush(RGB(255, 128, 128));
	HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);
	
	Rectangle(hDC, rtGrid.left, rtGrid.top, rtGrid.right, rtGrid.bottom);
	
	SetBkMode(hDC, TRANSPARENT);
	DrawText(hDC, _T("To Paint this rectangle with Solid Brush"), -1, &rtGrid, DT_VCENTER|DT_CENTER|DT_SINGLELINE);

	SelectObject(hDC, hOldBrush);
	RestoreDC(hDC, nSavedDC);

	return;
}

void CDemoWnd::DemoPatternBrush(HDC hDC, RECT& rtGrid)
{
	int nSavedDC = SaveDC(hDC);

	HBITMAP hBmp		= LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_PATTERN));
	HBRUSH  hBrush		= CreatePatternBrush(hBmp);
	HBRUSH  hOldBrush	= (HBRUSH)SelectObject(hDC, hBrush);

	InflateRect(&rtGrid, -5, -5);
	Rectangle(hDC, rtGrid.left, rtGrid.top, rtGrid.right, rtGrid.bottom);

	SetBkColor(hDC, RGB(255, 0, 255));
	DrawText(hDC, _T("To Paint this rectangle with Pattern Brush"), -1, &rtGrid, DT_VCENTER|DT_CENTER|DT_SINGLELINE);

	SelectObject(hDC, hOldBrush);
	DeleteObject(hBmp);
	DeleteObject(hBrush);

	RestoreDC(hDC, nSavedDC);

	return;
}

void CDemoWnd::DemoHatchBrush(HDC hDC, RECT& rtGrid)
{
	int nSavedDC = SaveDC(hDC);

	const int nHatchType[] = {
		HS_BDIAGONAL,	// 45-degree upward left-to-right hatch
		HS_CROSS,		// Horizontal and vertical crosshatch 
		HS_DIAGCROSS,	// 45-degree crosshatch 
		HS_FDIAGONAL,	// 45-degree downward left-to-right hatch 
		HS_HORIZONTAL,	// Horizontal hatch 
		HS_VERTICAL		// Vertical hatch
	};

	InflateRect(&rtGrid, -5, -5);

	const int nBlank		= 10;
	const int nBlockCount	= sizeof(nHatchType) / sizeof(*nHatchType);
	const int nBlockWidth	= (rtGrid.right - rtGrid.left) / nBlockCount; 

	for (int ii = 0; ii < nBlockCount; ii++)
	{
		HBRUSH hBrush = CreateHatchBrush(nHatchType[ii], RGB(30, 33, 120));
		HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);
		
		int nLeft = rtGrid.left + ii * nBlockWidth;
		Rectangle(hDC, nLeft + nBlank, rtGrid.top, nLeft + nBlockWidth, rtGrid.bottom);

		SelectObject(hDC, hOldBrush);
		DeleteObject(hBrush);
	}

	SetBkColor(hDC, RGB(128, 128, 0));
	DrawText(hDC, _T("To Paint this rectangle with Hatch Brush"), -1, &rtGrid, DT_VCENTER|DT_CENTER|DT_SINGLELINE);

	RestoreDC(hDC, nSavedDC);
}

void CDemoWnd::DemoKindOfBrush(HDC hDC, RECT& rtGrid)
{
	int nSavedDC = SaveDC(hDC);
	
	InflateRect(&rtGrid, -5, -5);
	
	const int nBlockCount	= 4;
	const int nBlank		= 10;
	const int nBlockW		= (rtGrid.right - rtGrid.left) / nBlockCount;

	RECT rtBlocks[nBlockCount];
	for (int ii = 0; ii < nBlockCount; ii++)
	{
		int nLeft = rtGrid.left + ii * nBlockW;
		SetRect(&rtBlocks[ii], nLeft + ((0 != ii) ? nBlank : 0), rtGrid.top, nLeft + nBlockW, rtGrid.bottom);
	}

	LOGBRUSH LogBrush[nBlockCount];

	//--: Solid Brush
	LogBrush[0].lbStyle	= BS_SOLID;
	LogBrush[0].lbColor	= RGB(234, 233, 21);
	LogBrush[0].lbHatch	= 0;
	
	//--: Pattern Brush
	LogBrush[1].lbStyle	= BS_PATTERN;
	LogBrush[1].lbColor = DIB_RGB_COLORS;
	LogBrush[1].lbHatch = (ULONG_PTR)LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_PATTERN));
	
	//--: Hatch Brush
	LogBrush[2].lbStyle = BS_HATCHED;
	LogBrush[2].lbColor = RGB(234, 233, 21);
	LogBrush[2].lbHatch = HS_CROSS;
	
	//--: Transparent Brush
	LogBrush[3].lbStyle = BS_NULL;
	LogBrush[3].lbColor = 0;
	LogBrush[3].lbHatch = 0;

	for (int ii = 0; ii < nBlockCount; ii++)
	{	
		HBRUSH hBrush	 = CreateBrushIndirect(&LogBrush[ii]);
		HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush);		

		Rectangle(hDC, rtBlocks[ii].left, rtBlocks[ii].top, rtBlocks[ii].right, rtBlocks[ii].bottom);

		SelectObject(hDC, hOldBrush);
		DeleteObject(hBrush);
	}
	DeleteObject((HBITMAP)LogBrush[1].lbHatch);

	SetBkColor(hDC, RGB(128, 128, 128));
	DrawText(hDC, _T("To Paint this rectangle with a kind of brush"), -1, &rtGrid, DT_VCENTER|DT_CENTER|DT_SINGLELINE);

	RestoreDC(hDC, nSavedDC);

	return;
}